
namespace Stee.CAP8.MessageBus.Sample.Factories
{
    using System;
    using System.Collections.Generic;
    using Stee.CAP8.MessageBus.Interface.Delegates;
    using Stee.CAP8.MessageBus.Interface.Interfaces;
    using Stee.CAP8.MessageBus.Interface.Models;
    using Stee.CAP8.MessageBus.Kafka.Configurations;
    using Stee.CAP8.MessageBus.Kafka.Publisher;
    using Stee.CAP8.MessageBus.Kafka.Subscriber;
    using static Stee.CAP8.MessageBus.Interface.Delegates.MessageDelegates;

    /// <summary>
    /// Message bus factory for setting up kafka and creating subscribers & publishers
    /// </summary>
    /// <typeparam name="TConfig">Broker configuration data type</typeparam>
    public class KafkaMessageBusFactory<TConfig> : IMessageBusFactory<TConfig>
    {
        #region Constant & Static Variables

        //private readonly static Logger logger;

        #endregion Constant & Static Variables


        #region Fields

        /// <summary>
        /// Admin configuration
        /// </summary>
        private AdminConfiguration adminConfiguration;

        /// <summary>
        /// Publisher configuration
        /// </summary>
        private PublisherConfiguration publisherConfiguration;

        /// <summary>
        /// Subscriber configuration
        /// </summary>
        private SubscriberConfiguration subscriberConfiguration;

        ///// <summary>
        ///// Collection map of publishers
        ///// </summary>
        //private readonly Dictionary<TopicName, IDisposable> publishers = new Dictionary<TopicName, IDisposable>();

        ///// <summary>
        ///// Collection map of subscribers
        ///// </summary>
        //private readonly Dictionary<TopicName, IDisposable> subscribers = new Dictionary<TopicName, IDisposable>();

        #endregion Fields


        #region Properties

        /// <summary>
        /// Gets the flag indicating if factory is initialized
        /// </summary>
        public bool IsInitialized { get; private set; } = false;

        #endregion Properties


        #region Constructors

        /// <summary>
        /// Initializes a new instance of KafkaMessageBusFactory class
        /// </summary>
        public KafkaMessageBusFactory()
        {
            //// TODO: Parse information from config file or server call
            this.adminConfiguration = new AdminConfiguration(new Dictionary<string, string>
            {
                { "BootstrapServers", "127.0.0.1:9092" },
            });

            this.publisherConfiguration = new PublisherConfiguration(new Dictionary<string, string>
            {
                { "BootstrapServers", "127.0.0.1:9092" },
                { "Acks", "All" },
                { "ClientID", "mypublisher" },
                { "EnableIdempotence", "true" },
                { "LingerMs", "0.5" },
                { "MessageSendMaxRetries", "2" },
                { "MessageTimeoutMs", "300000" },
                { "QueueBufferingMaxKbytes", "1048576" },
                { "QueueBufferingMaxMessages", "100000" },
            });

            this.subscriberConfiguration = new SubscriberConfiguration(new Dictionary<string, string>
            {
                { "BootstrapServers", "127.0.0.1:9092" },
                { "GroupID", "mygroup" },
                { "ClientID", "mysubscriber" },
                { "EnableAutoCommit", "true" },
                { "AutoCommitIntervalMs", "5000" },
                { "EnableAutoOffsetStore", "true" },
            });

            ////// Initialize the configurations and mappings
            //this.publishers = new Dictionary<TopicName, IDisposable>();
            //this.subscribers = new Dictionary<TopicName, IDisposable>();
        }

        #endregion Constructors


        /// <summary>
        /// Initialize the message bus factory
        /// </summary>
        /// <param name="username">Username, nullable</param>
        /// <param name="password">Password, nullable</param>
        /// <param name="configurations">Broker configurations, nullable</param>
        public void Initialize(string username, string password, TConfig configurations)
        {
            try
            {
                //// Initialize other settings
                //// TODO: Setup admin config for kafka topics, partitions, replica factor and others
                if (configurations != null)
                {

                }

                this.IsInitialized = true;
            }
            catch (Exception ex)
            {

                throw;
            }
        }


        /// <summary>
        /// Register/create new publisher
        /// </summary>
        /// <typeparam name="TMessage">Message data type</typeparam>
        /// <param name="topicName">Message topic</param>
        /// <param name="publishResponseHandler">Handler for published topic message</param>
        /// <returns>Return new publisher</returns>
        public IDisposable RegisterPublisher<TMessage>(TopicName topicName, HandlePublishResponse<TMessage> publishResponseHandler)
        {
            try
            {
                return new PublisherImpl<TMessage>(topicName, this.publisherConfiguration, publishResponseHandler);
            }
            catch (Exception ex)
            {

                throw;
            }
        }

        /// <summary>
        /// Register/create new subscriber
        /// </summary>
        /// <typeparam name="TMessage">Message data type</typeparam>
        /// <param name="topicName">Topic name</param>
        /// <param name="subscribeTopicHandler">Handler for subscribed topic message</param>
        /// <returns>Return new subscriber</returns>
        public IDisposable RegisterSubscriber<TMessage>(TopicName topicName, HandleSubscribeTopic<TMessage> subscribeTopicHandler)
        {
            try
            {
                return new SubscriberImpl<TMessage>(topicName, this.subscriberConfiguration, subscribeTopicHandler);
            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            //this.Dispose(true);
            //GC.SuppressFinalize()
        }




        private void CheckFactoryState()
        {
            if (!this.IsInitialized)
            {
                //Logger.Fatal("Message bus factory must be initialized before access.");
                throw new TypeInitializationException(this.GetType().FullName, null);
            }
        }
    }
}
